# coding: utf-8
import base64
import hashlib
import hmac
import json
import time
import traceback
import urllib
import datetime
import requests

from django.contrib.auth import login
from django.template.defaultfilters import urlencode
from django.http import HttpResponse, HttpResponseRedirect
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings
from rest_framework.views import APIView
from rest_framework_jwt.serializers import jwt_payload_handler

from account.models import User
from account.serializers import FetchAccountUserSerializer
from common import DING_LOGIN_APP_SECRET, DING_LOGIN_APP_ID, STATE_VAL, AgentId, DINGTALK_BASE_URL
from common.ding_client import DingClient
from common.callback_manager import CallbackManager
from ding_platform.permissions import CwspPermission
from config.settings.base import logger, GET_DINGTALK_CODE_URL


class DingCallbackView(APIView):
    """
    钉钉回调事件视图类
    """

    permission_classes = (CwspPermission,)

    def post(self, request):
        """
        钉钉回调消息
        """
        callback_info = request.data.get('callback_info')
        logger.info('get callback from dingtalk...')
        callback_info = json.loads(callback_info)
        logger.info(callback_info)

        # 处理事件
        event_type = callback_info.get('EventType')
        getattr(CallbackManager(), event_type)(callback_info)
        return HttpResponse('success')


class SyncDataView(APIView):
    """
    同步数据
    """
    permission_classes = (AllowAny,)

    def get(self, request):
        """
        钉钉回调消息
        """
        client = DingClient()
        client.sync_corp()
        return Response(data='ok')


class JsApiView(APIView):
    """
    计算前端校验需要使用的签名信息
    """
    permission_classes = (IsAuthenticated,)

    def get(self, request, *args, **kwargs):
        """
        :param request:
        :return:
        """
        client = DingClient()
        data = client.get_jsapi_params(DINGTALK_BASE_URL)
        data["agentId"] = AgentId
        return Response(data=data)


class AccessTokenApiView(APIView):
    """
    access_token
    """
    permission_classes = (IsAuthenticated, )

    def get(self, request, *args, **kwargs):
        """
        access_token
        :param request:
        :return:
        """
        client = DingClient()
        access_token = client.access_token
        return Response(data={"access_token": access_token})


def user_login(request):
    """
    @summary: web端：扫码登录功能
    @author:
    @return:
    """
    token = request.COOKIES.get('token')
    next_page = request.GET.get('next', '/')
    if token:
        return HttpResponseRedirect(next_page)
    else:
        redirect_url = urlencode(GET_DINGTALK_CODE_URL + '?next=' + next_page)
        dingtalk_code_url = 'https://oapi.dingtalk.com/connect/qrconnect?' \
                            'appid={app_id}&response_type=code&scope=' \
                            'snsapi_login&state={state}&redirect_uri=' \
                            '{redirect_url}'.format(app_id=DING_LOGIN_APP_ID,
                                                    state=STATE_VAL,
                                                    redirect_url=redirect_url)
        return HttpResponseRedirect(dingtalk_code_url)


def get_dingtalk_code(request):
    """
    接收钉钉code参数
    """
    code = request.GET.get('code')
    next_page = request.GET.get('next', '/')
    timestamp = str(int(time.time() * 1000))
    message = timestamp
    sec = DING_LOGIN_APP_SECRET
    signature = base64.b64encode(
        hmac.new(sec.encode('utf-8'), message.encode('utf-8'),
                 digestmod=hashlib.sha256).digest())
    query_dct = {
        'signature': signature,
        'timestamp': timestamp,
        'accessKey': DING_LOGIN_APP_ID
    }

    query_str = urllib.parse.urlencode(query_dct)
    res = requests.post(
        'https://oapi.dingtalk.com/sns/getuserinfo_bycode?' + query_str,
        headers={'Content-Type': 'application/json'},
        data=json.dumps({'tmp_auth_code': code}),
        timeout=10,
    )
    if res.status_code == 200:
        content = json.loads(res.content)
        logger.info(content)
        user_info = content.get('user_info')
        unionid = user_info.get('unionid')
        client = DingClient()
        ret = client.user.get_userid_by_unionid(unionid)
        userid = ret['userid']
        try:
            user = User.objects.get(username=userid)
            login(request, user)
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            logger.info('token:' + str(token))
            redirect = HttpResponseRedirect(next_page)
            expiration = (datetime.datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA)
            redirect.delete_cookie(api_settings.JWT_AUTH_COOKIE)
            redirect.set_cookie(api_settings.JWT_AUTH_COOKIE, token,
                                expires=expiration)
            redirect.set_cookie("userid", user.username, expires=expiration)
            return redirect
        except Exception:
            logger.error(traceback.format_exc())
    return HttpResponseRedirect('/')


def dd_login(request):
    """
    钉钉端：登录功能
    """
    code = request.POST.get('code')
    next_page = request.GET.get('next', '/')
    if code:
        try:
            client = DingClient()
            ret = client.user.getuserinfo(code)
            user_id = ret.get('userid')
            if user_id:
                user = User.objects.get(username=user_id)
                jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                payload = jwt_payload_handler(user)
                token = jwt_encode_handler(payload)
                logger.info('token:' + str(token))
                response = HttpResponse(json.dumps({
                    'token': token,
                    'user': FetchAccountUserSerializer(instance=user).data
                }))
                logger.info('HTTP_STATE1:{},{}'.format(response.status_code, response))
                expiration = (datetime.datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA)
                response.delete_cookie(api_settings.JWT_AUTH_COOKIE)
                response.set_cookie(api_settings.JWT_AUTH_COOKIE, token, expires=expiration)
                response.set_cookie("userid", user_id, expires=expiration)
                logger.info('HTTP_STATE2:{},{}'.format(response.status_code, response))
                return response
        except Exception:
            logger.error(code)
            logger.error(traceback.format_exc())
    else:
        logger.error('AnonymousUser')
    return HttpResponseRedirect(next_page)
